package com.guaoran.distributed.io.nio.one.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * @author : guaoran
 * @Description NIO Server demo
 *  可以配合 BIOClient 测试
 * @date :2019/4/18 20:59
 */
public class NIOServerDemo {
    Selector selector;
    public NIOServerDemo(int port){
        if(port==0)
            port = 8080;
        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(port));
            //设置为非阻塞，默认是阻塞
            serverSocketChannel.configureBlocking(false);
            // 打开selector 选择器
            selector = Selector.open();
            // 注册监听连接事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("NIO 服务已经启动，监听："+port+" 端口");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void listener() throws IOException {
        while(true){
            // 获得等待的数量，此处不会阻塞
            int wait = selector.select();
            if(wait == 0 ){
                continue;
            }
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                //处理业务逻辑
                process(key);
                //删除处理过的
                iterator.remove();
            }
        }
    }

    private void process(SelectionKey key) throws IOException {
        // 分配1024 个字节大小的 buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        // 如果可用
        if(key.isAcceptable()) {
            ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
            SocketChannel client = serverSocketChannel.accept();
            // 设置非阻塞
            client.configureBlocking(false);
            // 注册可读事件
            client.register(selector,SelectionKey.OP_READ);
        }else if (key.isReadable()){
            // 可读
            SocketChannel client = (SocketChannel) key.channel();
            int len = client.read(byteBuffer);
            if(len>0){
                // 重新设置缓冲区，即前面写好的数据将不会再被改变
                byteBuffer.flip();
                String content = new String(byteBuffer.array(),0,len);
                System.out.println(content);
                // 注册可写事件
                client.register(selector,SelectionKey.OP_WRITE);
            }
            byteBuffer.clear();
        }else if (key.isWritable()){
            // 可写
            SocketChannel client = (SocketChannel) key.channel();
            // 包装一个现有的数组 并输出
            client.write(byteBuffer.wrap("Hello ervery one ".getBytes()));
            client.close();
        }
    }

    public static void main(String[] args) throws IOException {
        new NIOServerDemo(8080).listener();
    }
}
